// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// ignore_for_file: prefer_expression_function_bodies

import 'dart:io';

import 'package:args/args.dart';
import 'package:json_syntax_generator/json_syntax_generator.dart';

import '../test/schema/helpers.dart';

const generateFor = ['hooks', 'code_assets', 'data_assets'];

final rootSchemas = loadSchemas([
  packageUri.resolve('doc/schema/'),
  packageUri.resolve('../code_assets/doc/schema/'),
  packageUri.resolve('../data_assets/doc/schema/'),
]);

void main(List<String> args) {
  final stopwatch = Stopwatch()..start();
  final parser = ArgParser()
    ..addFlag(
      'set-exit-if-changed',
      negatable: false,
      help: 'Return a non-zero exit code if any files were changed.',
    )
    ..addFlag(
      'd',
      negatable: false,
      help: 'Dump analyzed schema to .g.txt file.',
    );
  final argResults = parser.parse(args);

  final setExitIfChanged = argResults['set-exit-if-changed'] as bool;
  final dumpAnalyzedSchema = argResults['d'] as bool;
  var generatedCount = 0;
  var changedCount = 0;

  for (final packageName in generateFor) {
    const schemaName = 'shared';
    final schemaUri = packageUri.resolve(
      '../$packageName/doc/schema/$schemaName/shared_definitions.schema.json',
    );
    final schema = rootSchemas[schemaUri]!;
    final analyzedSchema = SchemaAnalyzer(
      schema,
      nameOverrides: {
        'ios': 'iOS',
        'Ios': 'IOS',
        'macos': 'macOS',
        'Macos': 'MacOS',
        'CodeAssetsCodeAsset': 'NativeCodeAssetNew',
        'DataAssetsDataAsset': 'DataAssetNew',
      },
      publicSetters: [
        'BuildOutput',
        'Config',
        'ConfigExtensions',
        'HookInput',
        'HookOutput',
        'LinkOutput',
      ],
      visbleUnionTagValues: ['Asset'],
    ).analyze();
    final textDumpFile = File.fromUri(
      packageUri.resolve('../$packageName/lib/src/$packageName/syntax.g.txt'),
    );

    final newTextDumpContent = analyzedSchema.toString();
    if (dumpAnalyzedSchema) {
      var oldTextDumpContent = '';
      if (textDumpFile.existsSync()) {
        oldTextDumpContent = textDumpFile.readAsStringSync();
      }
      if (oldTextDumpContent != newTextDumpContent) {
        textDumpFile.writeAsStringSync(newTextDumpContent);
        print('Generated ${textDumpFile.uri}');
        changedCount += 1;
      }
      generatedCount += 1;
    } else if (textDumpFile.existsSync()) {
      textDumpFile.deleteSync();
      print('Deleted ${textDumpFile.uri}');
      changedCount += 1;
    }

    final output = SyntaxGenerator(
      analyzedSchema,
      header:
          '''
// This file is generated, do not edit.
// File generated by pkgs/hooks/tool/generate_syntax.dart.
// Must be rerun when pkgs/$packageName/doc/schema/ is modified.
''',
    ).generate();
    final outputUri = packageUri.resolve(
      '../$packageName/lib/src/$packageName/syntax.g.dart',
    );
    final outputFile = File.fromUri(outputUri);
    var oldOutputContent = '';
    if (outputFile.existsSync()) {
      oldOutputContent = outputFile.readAsStringSync();
    }

    if (oldOutputContent != output) {
      outputFile.writeAsStringSync(output);
    }

    Process.runSync(Platform.executable, ['format', outputUri.toFilePath()]);

    final newOutputContent = outputFile.readAsStringSync();

    final newContentNormalized = newOutputContent.replaceAll('\r\n', '\n');
    final oldContentNormalized = oldOutputContent.replaceAll('\r\n', '\n');
    if (newContentNormalized != oldContentNormalized) {
      print('Generated $outputUri');
      changedCount += 1;
    }
    generatedCount += 1;
  }

  stopwatch.stop();
  final duration = stopwatch.elapsedMilliseconds / 1000.0;
  print(
    'Generated $generatedCount files ($changedCount changed) in '
    '${duration.toStringAsFixed(2)} seconds.',
  );
  if (setExitIfChanged && changedCount > 0) {
    exit(1);
  }
}

Uri packageUri = findPackageRoot('hooks');
